/*
 * jxUtils Project (2014)
 * 
 * by Denilson Edinaldo Pinto
 * 
 * LGPL
 * Copyright (C) 2014
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.jxUtils.system;

import static org.jxUtils.JXConstants.TEXT_NEW_LINE;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import org.jxUtils.check.CheckUtil;
import org.jxUtils.i18n.I18N;

/**
 * @author Denilson Edinaldo Pinto
 * @porject jxUtils
 * @package org.jxUtils.system
 * @date 15/11/2014 - 17:32:06
 */
public final class SystemUtil {
	
	public static final String PING = "ping";
	
	/**
	 * @param value
	 * @param by
	 * @throws UnsupportedOperationException
	 * @throws Exception
	 */
	private static synchronized boolean killProcess(Object value, String by) throws UnsupportedOperationException, Exception {
	
		//
		if(OperatingSystem.isWindows()) {
			
			String line = null;
			
			Process process = Runtime.getRuntime().exec("tasklist.exe /fo csv /nh");
			
			BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			
			//
			while((line = reader.readLine()) != null) {
				
				//
				if(CheckUtil.isNotAbsoluteEmpty(line)) {
					
					//
					if(line.toString().split(",")[1].replace("\"", "").equals(value)) {
						
						Runtime.getRuntime().exec("taskkill /F /" + by + " " + line.substring(1, line.indexOf("\"", 1)));
						
						return true;
					}
				}
			}
			
			reader.close();
			
		}else if(OperatingSystem.isPosix()) {
			
			Runtime.getRuntime().exec((by.equals("PID") ? "kill -9 " : "killall ") + value);
			
			return true;
			
		}else {
			
			throw new UnsupportedOperationException(I18N.system().notSupportedOperatingSystem());
		}
		
		return false;
	}
	
	/**
	 * @return The Operating System Architecture
	 */
	public static String getArchitecture() {
	
		return OperatingSystem.getArchitecture();
	}
	
	/**
	 * @return the amount of virtual memory that is guaranteed to
	 *         be available to the running process in bytes,
	 *         or <tt>-1</tt> if this operation is not supported.
	 */
	public static long getCommittedVirtualMemorySize() {
	
		return OperatingSystem.getCommittedVirtualMemorySize();
	}
	
	/**
	 * @return the amount of virtual memory that is guaranteed to
	 *         be available to the running process
	 */
	public static String getCommittedVirtualMemorySizeInString() {
	
		return OperatingSystem.getCommittedVirtualMemorySizeInString();
	}
	
	/**
	 * @return the amount of free physical memory in bytes, or <tt>-1</tt> if this operation is not supported.
	 */
	public static long getFreePhysicalMemorySize() {
	
		return OperatingSystem.getFreePhysicalMemorySize();
	}
	
	/**
	 * @return the amount of free physical memory
	 */
	public static String getFreePhysicalMemorySizeInString() {
	
		return OperatingSystem.getFreePhysicalMemorySizeInString();
	}
	
	/**
	 * @return the amount of free swap space in bytes, or <tt>-1</tt> if this operation is not supported.
	 */
	public static long getFreeSwapSpaceSize() {
	
		return OperatingSystem.getFreeSwapSpaceSize();
	}
	
	/**
	 * @return the amount of free swap space
	 */
	public static String getFreeSwapSpaceSizeInString() {
	
		return OperatingSystem.getFreeSwapSpaceSizeInString();
	}
	
	/**
	 * @return The Kernel Version (OS Version)
	 */
	public static String getKernelVersion() {
	
		return OperatingSystem.getKernelVersion();
	}
	
	/**
	 * Returns the name of the current operating system platform as listed in the System properties.
	 */
	public static String getOSName() {
	
		return OperatingSystem.getName();
	}
	
	/**
	 * @return The Operating System Version
	 */
	public static String getOSVersion() {
	
		return OperatingSystem.getVersion();
	}
	
	/**
	 * Returns the "recent cpu usage" for the Java Virtual Machine process.
	 * This value is a double in the [0.0,1.0] interval. A value of 0.0 means
	 * that none of the CPUs were running threads from the JVM process during
	 * the recent period of time observed, while a value of 1.0 means that all
	 * CPUs were actively running threads from the JVM 100% of the time
	 * during the recent period being observed. Threads from the JVM include
	 * the application threads as well as the JVM internal threads. All values
	 * betweens 0.0 and 1.0 are possible depending of the activities going on
	 * in the JVM process and the whole system. If the Java Virtual Machine
	 * recent CPU usage is not available, the method returns a negative value.
	 *
	 * @return the "recent cpu usage" for the Java Virtual Machine process;
	 *         a negative value if not available.
	 * @since 1.7
	 */
	public static double getProcessCpuLoad() {
	
		return OperatingSystem.getProcessCpuLoad();
	}
	
	/**
	 * @return the CPU time used by the process in nanoseconds,
	 *         or <tt>-1</tt> if this operation is not supported.
	 */
	public static long getProcessCpuTime() {
	
		return OperatingSystem.getProcessCpuTime();
	}
	
	/**
	 * @return the CPU time used by the process
	 */
	public static String getProcessCpuTimeInString() {
	
		return OperatingSystem.getProcessCpuTimeInString();
	}
	
	/**
	 * @return Process List
	 * @throws UnsupportedOperationException
	 * @throws Exception
	 */
	public static synchronized List<String> getProcessList() throws UnsupportedOperationException, Exception {
	
		List<String> list = new ArrayList<String>();
		
		String line = null;
		
		Process process = null;
		
		//
		if(OperatingSystem.isWindows()) {
			
			process = Runtime.getRuntime().exec("tasklist.exe /V /fo table");
			
		}else if(OperatingSystem.isPosix()) {
			
			process = Runtime.getRuntime().exec("ps aux");
			
		}else {
			
			throw new UnsupportedOperationException(I18N.system().notSupportedOperatingSystem());
		}
		
		BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
		
		//
		while((line = reader.readLine()) != null) {
			
			//
			if(CheckUtil.isNotAbsoluteEmpty(line)) {
				
				list.add(line);
			}
		}
		
		reader.close();
		
		return list;
	}
	
	/**
	 * @return Process List in String
	 * @throws UnsupportedOperationException
	 * @throws Exception
	 */
	public static synchronized String getProcessString() throws UnsupportedOperationException, Exception {
	
		StringBuilder strProcess = new StringBuilder("");
		
		List<String> list = getProcessList();
		
		//
		for(String process : list) {
			
			strProcess.append(process + TEXT_NEW_LINE);
		}
		
		return strProcess.toString();
	}
	
	/**
	 * Returns the "recent cpu usage" for the whole system. This value is a
	 * double in the [0.0,1.0] interval. A value of 0.0 means that all CPUs
	 * were idle during the recent period of time observed, while a value
	 * of 1.0 means that all CPUs were actively running 100% of the time
	 * during the recent period being observed. All values betweens 0.0 and
	 * 1.0 are possible depending of the activities going on in the system.
	 * If the system recent cpu usage is not available, the method returns a
	 * negative value.
	 *
	 * @return the "recent cpu usage" for the whole system; a negative
	 *         value if not available.
	 * @since 1.7
	 */
	public static double getSystemCpuLoad() {
	
		return OperatingSystem.getSystemCpuLoad();
	}
	
	/**
	 * @return the total amount of physical memory in bytes, or <tt>-1</tt> if this operation is not supported.
	 */
	public static long getTotalPhysicalMemorySize() {
	
		return OperatingSystem.getTotalPhysicalMemorySize();
	}
	
	/**
	 * @return the total amount of physical memory
	 */
	public static String getTotalPhysicalMemorySizeInString() {
	
		return OperatingSystem.getTotalPhysicalMemorySizeInString();
	}
	
	/**
	 * @return the total amount of swap space in bytes, or <tt>-1</tt> if this operation is not supported.
	 */
	public static long getTotalSwapSpaceSize() {
	
		return OperatingSystem.getTotalSwapSpaceSize();
	}
	
	/**
	 * @return the total amount of swap space
	 */
	public static String getTotalSwapSpaceSizeInString() {
	
		return OperatingSystem.getTotalSwapSpaceSizeInString();
	}
	
	/**
	 * Returns whether or not the current operating system is the Apple Macintosh OS X platform.
	 */
	public static boolean isMac() {
	
		return OperatingSystem.isMac();
	}
	
	/**
	 * Returns whether or not the current operating system is a Posix-compatible platform (Unix, Linux, Solaris, etc).
	 */
	public static boolean isPosix() {
	
		return OperatingSystem.isPosix();
	}
	
	/**
	 * Returns whether or not the current operating system is a Microsoft Windows platform.
	 */
	public static boolean isWindows() {
	
		return OperatingSystem.isWindows();
	}
	
	/**
	 * @param processPID
	 * @throws UnsupportedOperationException
	 * @throws Exception
	 */
	public static synchronized boolean killProcess(int processPID) throws UnsupportedOperationException, Exception {
	
		return killProcess(processPID, "PID");
	}
	
	/**
	 * @param processName
	 * @throws UnsupportedOperationException
	 * @throws Exception
	 */
	public static synchronized boolean killProcess(String processName) throws UnsupportedOperationException, Exception {
	
		return killProcess(processName, "IM");
	}
	
	/**
	 * @param ip
	 * @param iterations
	 * @param sysout
	 * @return response
	 * @throws IOException
	 */
	public static synchronized StringBuilder ping(String ip, int iterations, boolean sysout) throws IOException {
	
		String cmd = PING + " " + ip;
		
		StringBuilder response = new StringBuilder("");
		StringBuilder resp = null;
		
		int iteration = 0;
		
		@SuppressWarnings("resource")
		Scanner scanner = new Scanner(Runtime.getRuntime().exec(cmd).getInputStream());
		
		//
		while(iteration < iterations && scanner.hasNextLine()) {
			
			resp = new StringBuilder(scanner.nextLine());
			
			//
			if(sysout) {
				
				System.out.println(resp);
			}
			
			response.append(resp);
			response.append(TEXT_NEW_LINE);
			
			iteration++;
		}
		
		return response;
	}
}
